package com.feib.soeasy.action;

import java.io.StringReader;
import java.util.Calendar;
import java.util.Date;

import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.DontBind;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.action.StreamingResolution;
import net.sourceforge.stripes.integration.spring.SpringBean;
import net.sourceforge.stripes.validation.LocalizableError;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidateNestedProperties;
import net.sourceforge.stripes.validation.ValidationErrorHandler;
import net.sourceforge.stripes.validation.ValidationErrors;

import org.springframework.security.authentication.encoding.Md5PasswordEncoder;

import com.feib.soeasy.model.Group;
import com.feib.soeasy.model.User;
import com.feib.soeasy.model.UserLoginControl;
import com.feib.soeasy.pagination.PaginatedList;
import com.feib.soeasy.service.GroupService;
import com.feib.soeasy.service.UserLoginControlService;
import com.feib.soeasy.service.UserService;
import com.feib.soeasy.util.UserUtil;

/**
 * @title (#)Soez9001ActionBean.java <br>
 * @description 帳號維護作業 Controller<br>
 * @author Howie Yu
 * @version 1.0.0 2010/12/04
 * @copyright Far Eastern International Bank Copyright (c) 2010<br>
 * @2010/11/30 create by Howie Yu<br>
 */
public class Soez9001ActionBean extends BaseActionBean implements ValidationErrorHandler
{

    /**
     * 基本頁面
     */
    private static final String DEFAULT_JSP = "/WEB-INF/views/soez9001/soez9001.jsp";

    /**
     * 帳單業者帳號查詢結果畫面
     */
    private static final String AJAX_QUERY_JSP = "/WEB-INF/views/soez9001/soez9001List.jsp";

    /**
     * 維護模式資料
     */
    private static final String AJAX_QUERY_USER_JSP = "/WEB-INF/views/soez9001/appUserDetail.jsp";

    /**
     * 業者代號查詢畫面
     */
    private static final String AJAX_QUERY_GROUP_JSP = "/WEB-INF/views/soez9001/groupPopUpList.jsp";

    /**
     * 查詢條件
     */
    private User qryUser;

    /**
     * 帳單業者查詢條件
     */
    private Group qryGroup;

    @SpringBean(value = "soeasyPasswordEncoder")
    private Md5PasswordEncoder md5PasswordEncoder;

    /**
     * 查詢條件-使用者Id
     */
    @Validate(required = false, on = {"doAjaxQuery"})
    private String qryUserId;

    /**
     * 查詢條件-使用者名稱
     */
    @Validate(required = false, on = {"doAjaxQuery"})
    private String qryUserName;

    /**
     * 新增/修改 時使用
     */
    @ValidateNestedProperties({@Validate(field = "userPk", required = true, on = {"toAjaxEditUser"})})
    private User editUser;
    
    /**
     * 新增/修改 時使用
     */
    private UserLoginControl editUserLoginControl;

    @SpringBean("groupService")
    private GroupService groupService;

    @SpringBean("userService")
    private UserService userService;

    @SpringBean("userLoginControlService")
    private UserLoginControlService userLoginControlService;

    /**
     * 帳單業者查詢結果
     */
    private PaginatedList<Group> queryGroupResult;

    /**
     * 使用者查詢結果
     */
    private PaginatedList<User> queryResult;

    @DontBind
    @DefaultHandler
    public Resolution doDefault()
    {
        logger.debug("Enter doDefault mehtod.");
        return new ForwardResolution(DEFAULT_JSP);
    }

    /*
     * 相關Table如下說明
     * 
     * APP_GROUP:帳單業者資料
     * APP_USER: 帳號資料
     * APP_ROLE: 角色
     * 
     * 系統一建置後，會
     * 1. default 一筆 APP_GROUP 資料(銀行端，即遠銀)，不可刪除，可異動
     * 2. defualt 一筆 APP_ROLE='ADMINISTRATOR' , 銀行端系統管理角色 , 不可刪除，不可異動
     * 3. default 一筆 APP_USER=admin, 不可刪除，可異動密碼或不重要欄位
     * =================================================
     * 
     * 背景說明：
     * 銀行端建立一個帳單業者(APP_GROUP)的時候，同時會建立帳單業者 管理者的帳號，也就是背景會自動
     * 1. 一筆APP_ROLE='ADMINISTRATOR' 資料
     * 2. 一筆 APP_USER=admin 資料 這一組角色跟帳號，只有銀行端能夠維護。
     * 
     * 再說一個大前提：
     * 每一個Group(帳單業者)只可以修改同一個Group的帳號與角色，只有當Group是銀行端(GROUP_TYPE=1)的時候，才有例外
     * 
     * =================================================
     */

    /*
     * 以下是本程式簡略說明 銀行端 跟 帳單業者 都可以使用本程式
     * 
     * 1. 當登入者是銀行端人員, UserUtil.isBankGroup()= true
     * a. 顯示 業者代號 查詢條件若有輸入，則只帶出帳單業者的管理者ADMIN帳號(用ROLE='ADMINISTRATOR'去找)，
     * 不能管理帳單業者其他帳號
     * b. 當登入者具有ADMINISTRATOR的角色時候，才可以查到銀行端的 管理者帳號，否則須排除管理者帳號
     * 
     * 2. 當登入為 帳單業者
     * a. 沒有業者代號查詢條件
     * b. 查詢出來的grid 也沒有 業者代號 欄未顯示
     * c. 查詢條件強迫加入 Group條件，可參閱 Soez9004ActionBean 144行
     */

    /**
     * 帳單業者查詢
     * 
     * @return
     */
    public Resolution doAjaxQueryGroups()
    {
        logger.debug("------------Enter doAjaxQueryGroups mehtod.--------------------");
        try
        {
            // 如果不是銀行端，則查詢條件要加入帳單業者限制
            if(!UserUtil.isBankGroup())
            {
                throw new Exception("No Authority");
            }

            // USER未輸入查詢條件，所以查詢物件會是NULL(查詢物件不可為NULL)
            if(null == qryGroup)
                qryGroup = new Group();

            // 呼叫服務查詢
            queryGroupResult = groupService.queryByGroupExcludeBank(qryGroup,
                            queryGroupResult);
        }
        catch(Exception e)
        {
            logger.error("帳單業者查詢錯誤(Soez9001ActionBean.doAjaxQueryGroups):", e);

            // 轉換錯誤訊息
            ValidationErrors errors = new ValidationErrors();
            errors.addGlobalError(new LocalizableError("doAjaxQuery.exception"));
            getContext().setValidationErrors(errors);
            // 回傳 錯誤 HTML fragments
            return super.errorsToHtmlStreams(errors);
        }

        return new ForwardResolution(AJAX_QUERY_GROUP_JSP);
    }

    /**
     * 查詢業者代號，帶入使用者ID & name
     * 
     * @return
     */
    public Resolution doAjaxQuery()
    {
        logger.debug("--------------Enter doAjaxQuery mehtod-----------------------------");
        try
        {

            // USER未輸入查詢條件，所以查詢物件會是NULL(查詢物件不可為NULL)
            if(null == qryUser)
                qryUser = new User();
            
            
            // 銀行端 且有輸入業者代號，只能查詢管理者
            if(UserUtil.isBankGroup() && qryUser.getGroup() != null && qryUser.getGroup().getGroupNo() != null)
            {
                queryResult = userService.findPaginationForAdministratorByGroupNo(qryUser.getGroup().getGroupNo(), queryResult);
            }
            else
            {
                queryResult = userService.findPaginationUsers(UserUtil.getUserGroup().getGroupNo(), qryUser.getUserId(), qryUser.getUserName(), queryResult);
            }
            

//            // 如果不是銀行端，則查詢條件要加入帳單業者限制
//            if(!UserUtil.isBankGroup())
//            {
//                logger.debug(	"-----------------GroupPK:{}----------------------------",
//                                UserUtil.getUserGroup().getGroupNo());
//
//                // 判斷是否具有Admin權限
//
//                if(UserUtil.isAdminRole())
//                {
//                    queryResult = userService.queryUserPaginationByRole(qryUser.getUserId(),
//                                    qryUser.getUserName(),
//                                    UserUtil.getUserGroup().getGroupNo(),
//                                    ROLE_CONSTRAINT.IncludeThisRole,
//                                    null,
//                                    queryResult);
//                }
//                else
//                {
//                    queryResult = userService.queryUserPaginationByRole(qryUser.getUserId(),
//                                    qryUser.getUserName(),
//                                    UserUtil.getUserGroup().getGroupNo(),
//                                    ROLE_CONSTRAINT.WithoutThisRole,
//                                    UserUtil.ADMIN_ROLE,
//                                    queryResult);
//                }
//
//                // 呼叫服務查詢
//
//            }
//            else
//            {
//                logger.debug(	"-----------------BankGroup  userId:{}----------------------------",
//                                qryUser.getUserId());
//
//                Group group;
//                if(qryUser.getGroup() != null)
//                {
//                    group = qryUser.getGroup();
//                }
//                else
//                {
//                    group = new Group();
//                }
//                // 呼叫服務查詢
//                queryResult = userService.queryUserPaginationByRole(qryUser.getUserId(),
//                                qryUser.getUserName(),
//                                group.getGroupNo(),
//                                ROLE_CONSTRAINT.OnlyThisRole,
//                                UserUtil.ADMIN_ROLE,
//                                queryResult);
//
//            }

        }
        catch(Exception e)
        {
            logger.error("系統維護帳號查詢錯誤(Soez9001ActionBean.doAjaxQuery):", e);

            // 轉換錯誤訊息
            ValidationErrors errors = new ValidationErrors();
            errors.addGlobalError(new LocalizableError("doAjaxQuery.exception"));
            getContext().setValidationErrors(errors);
            // 回傳 錯誤 HTML fragments
            return super.errorsToHtmlStreams(errors);
        }

        return new ForwardResolution(AJAX_QUERY_JSP);
    }

    /**
     * 導向新增畫面
     * 
     * @return
     */
    public Resolution toAjaxAddUser()
    {

        logger.debug("=================Enter toAjaxAddUser mehtod.=====================");

        this.editUser = new User(); // 產生新的User 帳號

        return new ForwardResolution(AJAX_QUERY_USER_JSP);
    }

    /**
     * 導向修改畫面
     * 
     * @return
     */
    public Resolution toAjaxEditUser()
    {
        // 從資料庫取出資料
        this.editUser = this.userService.queryByUerPk(this.editUser.getUserPk());
        this.editUserLoginControl = userLoginControlService.findByUer(editUser);
        
        return new ForwardResolution(AJAX_QUERY_USER_JSP);
    }

    /**
     * 儲存使用者(新增/修改)
     * 
     * @return
     */
    public Resolution doAjaxSaveUser()
    {
        logger.debug("Enter doAjaxSaveUser method.");

        StringBuffer msg = new StringBuffer(); 
        try {

            if(this.editUser.getUserPk() == null)
            {
                // 先確認帳號是否已經有存在DB中了
                if (this.userService.isDuplicateUserId(editUser.getUserId(), UserUtil.getUserGroup().getGroupNo()))
                {
                    msg.append("帳號 ").append(editUser.getUserId()).append(" 已有人使用.");
                }
                else
                {
                    this.editUser.setGroup(UserUtil.getUserGroup());
                    this.editUser.setUserPassWord(createDefaultPassword());
                    this.editUser.setPwdExpiredDate(new Date()); // 密碼到期日為現在，強迫使用者登入時變更密碼

                    this.editUser.setCreatedBy(UserUtil.getUserName());
                    this.editUser.setCreatedDate(Calendar.getInstance().getTime());
                    this.editUser.setPwdErrorTime(new Integer(0));
                    this.editUser.setCaptchaErrorTime(new Integer(0));
                    
                    this.editUser.setLocked(Boolean.FALSE);

                    this.editUser.setUpdatedBy(UserUtil.getUserName());
                    this.editUser.setUpdatedDate(Calendar.getInstance().getTime());
                    this.userService.addUser(this.editUser);
                    msg.append("儲存成功").append("<input type='hidden' id='doAjaxSaveUserResultCode' value='1'/>");                 
                }
            }
            else
            {
                User userInDb = userService.queryByUerPk(this.editUser.getUserPk());
                userInDb.setUserEmail(this.editUser.getUserEmail());
                userInDb.setUserMemo(this.editUser.getUserMemo());
                userInDb.setUserName(this.editUser.getUserName());
                userInDb.setUserPhone(this.editUser.getUserPhone());
                userInDb.setEnabled(this.editUser.getEnabled());
                userInDb.setLocked(this.editUser.getLocked());
                
                userInDb.setUpdatedBy(UserUtil.getUserName());
                userInDb.setUpdatedDate(Calendar.getInstance().getTime());

                this.userService.saveUser(userInDb);
                msg.append("儲存成功").append("<input type='hidden' id='doAjaxSaveUserResultCode' value='1'/>");
            }
            
        }
        catch (Exception e) {
            logger.error("",e);
            msg.append("儲存失敗");
        }
        
        StreamingResolution resolution = new StreamingResolution("text/html", new StringReader(msg.toString()));
        resolution.setCharacterEncoding("UTF-8");
        return resolution;
    }

    /**
     * 
     * @return
     */
    private String createDefaultPassword()
    {
        String currentPwdMd5 = md5PasswordEncoder.encodePassword("0000",  null);

        return currentPwdMd5;

    }
    
    /**
     * 解鎖並且初始密碼
     * @return
     */
    public Resolution doUnlockUser()
    {
        logger.debug("Enter doUnlockUser method.");
        StringBuffer msg = new StringBuffer(); 
        try {
            User userInDb = userService.queryByUerPk(this.editUser.getUserPk());
            userInDb.setLocked(Boolean.FALSE);
            userInDb.setPwdErrorTime(new Integer(0));
            userInDb.setCaptchaErrorTime(new Integer(0));
            userInDb.setUserPassWord(createDefaultPassword());
            userInDb.setPwdExpiredDate(new Date());
            
            userInDb.setUpdatedBy(UserUtil.getUserName());
            userInDb.setUpdatedDate(Calendar.getInstance().getTime());

            this.userService.saveUser(userInDb);
            msg.append("解鎖成功").append("<input type='hidden' id='doUnlockUserResultCode' value='1'/>");   
        }
        catch (Exception e) {
            logger.error("",e);
            msg.append("解鎖失敗");
        }
        StreamingResolution resolution = new StreamingResolution("text/html", new StringReader(msg.toString()));
        resolution.setCharacterEncoding("UTF-8");
        return resolution;
    }

    // ================================================================================================

    /**
     * @return the qryGroup
     */
    public Group getQryGroup()
    {
        return qryGroup;
    }

    /**
     * @param qryGroup
     *            the qryGroup to set
     */
    public void setQryGroup(Group qryGroup)
    {
        this.qryGroup = qryGroup;
    }

    public User getQryUser()
    {
        return qryUser;
    }

    public void setQryUser(User qryUser)
    {
        this.qryUser = qryUser;
    }

    public String getQryUserId()
    {
        return qryUserId;
    }

    public void setQryUserId(String qryUserId)
    {
        this.qryUserId = qryUserId;
    }

    public String getQryUserName()
    {
        return qryUserName;
    }

    public void setQryUserName(String qryUserName)
    {
        this.qryUserName = qryUserName;
    }

    public PaginatedList<User> getQueryResult()
    {
        return queryResult;
    }

    public void setQueryResult(PaginatedList<User> queryResult)
    {
        this.queryResult = queryResult;
    }

    /**
     * @return the queryGroupResult
     */
    public PaginatedList<Group> getQueryGroupResult()
    {
        return queryGroupResult;
    }

    /**
     * @param queryGroupResult
     *            the queryGroupResult to set
     */
    public void setQueryGroupResult(PaginatedList<Group> queryGroupResult)
    {
        this.queryGroupResult = queryGroupResult;
    }

    /**
     * @return the editUser
     */
    public User getEditUser()
    {
        return editUser;
    }

    /**
     * @param editUser
     *            the editUser to set
     */
    public void setEditUser(User editUser)
    {
        this.editUser = editUser;
    }

    
    /**
     * @return the editUserLoginControl
     */
    public UserLoginControl getEditUserLoginControl() {
        return editUserLoginControl;
    }

    
    /**
     * @param editUserLoginControl the editUserLoginControl to set
     */
    public void setEditUserLoginControl(UserLoginControl editUserLoginControl) {
        this.editUserLoginControl = editUserLoginControl;
    }
    
    public UserLoginControl getUserLoginControlByUser(User user)
    {
        return userLoginControlService.findByUer(user);
    }
}
